package com.rpframework.module.common.bottom.service.impl;

import com.rpframework.core.json.FailException;
import com.rpframework.core.json.JsonResp;
import com.rpframework.core.json.ParameterException;
import com.rpframework.core.utils.MobileUtil;
import com.rpframework.module.common.bottom.service.SmsService;
import com.rpframework.module.common.bottom.sms.SmsTemplate;
import com.rpframework.module.common.config.Config;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;

import java.io.Serializable;
import java.util.concurrent.TimeUnit;

/**
 * 1.redis检测短信验证码 <br>
 * 2.发送短信http接口
 *
 * @author 刘兴
 */
public abstract class SmsServiceImpl implements SmsService {
    /**
     * 手机号码存入redis时模板类型与手机号码分隔符
     */
    private static final String redisSmsTemplateId = "{,}";
    /**
     * 获取时间
     */
    private static final int expireTime = 3600 * 8;

    private final RedisTemplate<Serializable, Serializable> redisTemplate;
    private final Config config;

    @Autowired
    public SmsServiceImpl(RedisTemplate<Serializable, Serializable> redisTemplate, Config config) {
        this.redisTemplate = redisTemplate;
        this.config = config;
    }

    @Override
    public boolean sendSmsByVerifyCode(String mobile, String content, String verifyCode, String smsTemplateId) {
        if (!MobileUtil.isPhoneBase(mobile)) {
            throw new ParameterException("手机号码不合法");
        }
        if (StringUtils.isBlank(content) || StringUtils.isBlank(verifyCode)) {
            SmsTemplate.SmsContentCode templateCode =
                    SmsTemplate.getTemplateCode(smsTemplateId);
            if (templateCode == null) {
                throw new ParameterException("内容/验证码为空？模板主键必传");
            }
            content = templateCode.getContent();
            verifyCode = templateCode.getCode()+"";
        }
        final String key = precast(mobile, smsTemplateId);

        String finalVerifyCode = verifyCode;
        boolean isSet = redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                connection.set(redisTemplate.getStringSerializer().serialize(key),
                        redisTemplate.getStringSerializer().serialize(finalVerifyCode));
                return true;
            }
        });

        if (!isSet) {
            return false;
        }
        // 发送短信
        boolean sendSMS = sendSms(mobile, content);
        if (!sendSMS) {
            return false;
        } else {
            // 过期时间
            redisTemplate.expire(key, expireTime, TimeUnit.MINUTES);
        }
        return true;
    }

    @Override
    public boolean checkSmsVerifyCode(String mobile, String verifyCode, String smsTemplateId)
            throws IllegalArgumentException {
        String code = redisTemplate.execute(new RedisCallback<String>() {
            @Override
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                byte[] key = redisTemplate.getStringSerializer().serialize(precast(mobile, smsTemplateId));

                if (connection.exists(key)) {
                    byte[] value = connection.get(key);
                    return redisTemplate.getStringSerializer().deserialize(value);
                }
                return null;
            }
        });

        if (StringUtils.isBlank(code)) {
            throw new ParameterException("验证码过期或还未获取验证码");
        } else {
            if (verifyCode.equalsIgnoreCase(code)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean sendSmsByVerifyCode(String mobile, String content, Integer verifyCode, Integer smsTemplateId) {
        return sendSmsByVerifyCode(mobile, content, verifyCode.toString(), smsTemplateId.toString());
    }

    @Override
    public boolean checkSmsVerifyCode(String mobile, Integer verifyCode, Integer smsTemplateId)
            throws IllegalArgumentException {
        return checkSmsVerifyCode(mobile, verifyCode.toString(), smsTemplateId.toString());
    }

    /**
     * 组装redis key
     *
     * @param mobile        手机号码
     * @param smsTemplateId 模板ID
     * @return 存入Redis key值
     */
    private String precast(String mobile, String smsTemplateId) {
        return config.getAppName() + "-->" + smsTemplateId + redisSmsTemplateId + mobile;
    }

    @Override
    public boolean sendSmsByVerifyCode(String mobile, String content, String smsTemplateId) {
        return sendSmsByVerifyCode(mobile, content, "", smsTemplateId);
    }

    @Override
    public boolean sendSmsByVerifyCode(String mobile, String content, Integer verifyCode, String smsTemplateId)
            throws IllegalArgumentException {
        return sendSmsByVerifyCode(mobile, content, verifyCode.toString(), smsTemplateId);
    }

    @Override
    public boolean sendSmsByVerifyCode(String mobile, String smsTemplateId) {
        return sendSmsByVerifyCode(mobile, null, smsTemplateId);
    }

    @Override
    public JsonResp sendSmsByVerifyCodeJson(String mobile, String smsTemplateId) {
        if (!sendSmsByVerifyCode(mobile, smsTemplateId)) {
            throw new FailException();
        }
        return new JsonResp().succ();
    }

}
